/*
Copyright (c) [2019年5月1日] [吴超]
[MBT_studio] is licensed under Mulan PSL v2.
You can use this software according to the terms and conditions of the Mulan PSL v2.
You may obtain a copy of Mulan PSL v2 at:
		 http://license.coscl.org.cn/MulanPSL2
THIS SOFTWARE IS PROVIDED ON AN "AS IS" BASIS, WITHOUT WARRANTIES OF ANY KIND,
EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO NON-INFRINGEMENT,
MERCHANTABILITY OR FIT FOR A PARTICULAR PURPOSE.
See the Mulan PSL v2 for more details.
*/
#pragma once

#include "引擎数据类型.h"
#include "core/设备内存缓存.h"
#include "core/shader_std.h"
#include "core/属性.h"

#include "向量.h"
#include "帧缓存.h"


#include <Windows.h>

#define FENCE_TIMEOUT 100000000


typedef void* T_渲染通道;

struct S_Mesh;




struct S_GPU计算 {
	S_设备环境	m_Ctx;
	S_着色*		m_Shader;
	S_管线*		m_Pipeline;
	
	std::vector<C_DescriptorSetLayout*>	m_着色参数布局;

	S_结构对象*				m_参数布局;
	S_结构指针				m_GPU参数set;

	S_GPU计算(S_设备环境* ctx);
	~S_GPU计算();

	void f_Dispatch();

};



struct S_绘图框架 {
	
	bool				m_是否暂停;
	std::vector<S_设备>	m_设备;
	E_绘图API			m_Type;
	S_设备环境          m_Ctx;

	
	//S_GPU参数设置描述 类型
	S_结构对象*     m_管线参数设置_None;
	S_结构对象*     m_管线参数设置_FS_1Tex;
	S_结构对象*     m_管线参数设置_FS_ImageArray;
	S_结构对象*     m_管线参数设置_FS_TAA;
	S_结构对象*     m_管线参数设置_VS_Proj;
	S_结构对象*     m_管线参数设置_VS_Mat4;

	S_结构对象*     m_管线参数设置_VS_WidgetTranform;
	S_结构对象*     m_管线参数设置_VS_WidgetColor;
	S_结构对象*     m_管线参数设置_VS_WidgetConvexRect;

	S_结构对象*     m_管线参数设置_FS_Textures;


	S_结构对象*		m_2D绘图管线布局集;
	


	C_DescriptorSetLayout* m_着色布局设置_None;
	C_DescriptorSetLayout* m_着色布局设置_VS_Proj;
	C_DescriptorSetLayout* m_着色布局设置_VS_Mat4;
	C_DescriptorSetLayout* m_着色布局设置_VS_WidgetTranform;
	C_DescriptorSetLayout* m_着色布局设置_Comp_L3_ImageSampleArray;
	//C_DescriptorSetLayout* m_着色布局设置_Comp_L4_SampleArray;
	C_DescriptorSetLayout* m_着色布局设置_CFS_L4_LayerArea;
	C_DescriptorSetLayout* m_着色布局设置_CFS_L4_SampleTAA;

	
	std::map<std::u16string, S_矢量字体> m_字体;

	C_场景渲染环境*			m_场景渲染环境;


	static S_子集绘图命令* g_资源加载管道;

	
	S_绘图框架();
	~S_绘图框架();


	virtual S_物理设备		f_取物理设备(uint8 id) { return {}; }
	virtual S_逻辑设备	f_创建图形逻辑设备(S_物理设备& dev, bool 是否有光追支持) { return { 0, -1 }; }
	virtual S_逻辑设备	f_创建计算逻辑设备(S_逻辑设备& dev) { return { 0, -1 }; }
	virtual S_逻辑设备	f_创建命令缓存(S_结构指针 dev) { return { 0, -1 }; }
	virtual S_逻辑设备	f_创建图形线管(S_结构指针 dev) { return { 0, -1 }; }


	virtual bool			f_创建同步围栏(S_逻辑设备& 逻辑dev) { return false; }
	

	virtual bool	f_创建窗口绘制面(S_设备环境& ctx, HINSTANCE& hInstance, HWND& hWnd, ivec2 size, E_MS次数 采样) { return false; }
	virtual void	f_重置交换链(S_设备环境& dev, ivec2 size, E_MS次数 采样) {}


	virtual bool	f_创建描述符() { return false; }
	virtual bool	f_创建深度模板视图(ivec2 size) { return false; }
	virtual void	f_beginRender(S_渲染环境* 绘图设备配置) {}
	virtual void	f_endRender(S_渲染环境* 绘图设备配置) {}

	virtual	void*	f_get设备() { return 0; }
	virtual	void*	f_get命令列表() { return 0; }
	virtual	void*	f_get环境() { return 0; }

};






void* f_df_getVK实例(S_绘图框架* df);
void f_df_销毁2D绘制缓存(S_设备环境& ctx);

void f_df_创建2D管线布局集(S_设备环境& ctx);
void f_df_销毁2D绘制参数布局(S_设备环境& ctx);


struct S_着色索引输入参数 {
	uint32		m_元素大小;
	E_数据格式	m_数据格式;
};


class S_GPU命令缓存 {
	S_设备环境	m_ctx;
	S_结构对象*	m_池;

public:
	S_GPU命令缓存(S_设备环境& ctx, uint32 线程数量 = 1);
	virtual ~S_GPU命令缓存();

	void f_创建命令缓存(uint32 线程索引 = 0);

	void f_begin(uint32 线程ID);
	void f_end(uint32 线程ID);
	void submit();

	void f_begin();
	void f_end();

};

struct S_着色 {
	int32 m_ShaderIndex;

	S_着色(const std::string& name);

	virtual void	f_init着色参数布局(const S_着色器创建配置& 参数配置, S_结构对象** 布局描述, uint32 布局描述数量) = 0;
	virtual void	f_alloc参数设置(S_结构指针* 描述集列表) = 0;
	virtual void	f_free参数设置(S_结构指针* 描述集列表) {};
	virtual void	f_销毁着色器(uint32 id) {};

	virtual void	f_构建顶点布局(const std::vector<S_着色顶点输入参数>& 参数配置) = 0;
	virtual void	f_构建管线布局(std::vector<C_DescriptorSetLayout*>& 参数配置, const std::vector<S_常量推送创建参数>& 常量) = 0;


};


struct S_节点实例着色器 : public S_着色 {
	S_节点实例着色器() :S_着色("节点实例着色器") {};
	virtual void	f_init着色参数布局(const S_着色器创建配置& 参数配置, S_结构对象** 布局描述, uint32 布局描述数量) {};
	virtual void	f_alloc参数设置(S_结构指针* 描述集列表) {};

	virtual void	f_构建顶点布局(const std::vector<S_着色顶点输入参数>& 参数配置) {};
	virtual void	f_构建管线布局(std::vector<C_DescriptorSetLayout*>& 参数配置, const std::vector<S_常量推送创建参数>& 常量) {};
};



void f_df_设置线管混合模式(S_线管创建参数& 创建参数, E_图层混合模式 混合模式);


struct S_管线 {
	S_设备环境* m_Ctx;
	uint32		m_管线绑定点;
	S_结构指针	m_线管布局;
	S_结构指针	m_线管;

	S_管线(const std::string& name);

	virtual void f_创建线管(const S_线管创建参数& 参数, S_着色& shader, E_管线槽 槽) {};
	virtual void f_创建线管(S_着色& shader) {};

	virtual void f_bind(const S_推送常量& push){};

};





Inline void f_df_init_GPU参数布局(S_GPU参数布局* layout) {
	layout->m_参数槽 = nullptr;
	layout->m_纹理槽 = nullptr;
	layout->m_绑定位置 = nullptr;

	layout->m_绑定数量 = 0;
	layout->m_纹理数量 = 0;
}

Inline void f_df_init_GPU参数槽(S_GPU参数槽* layout) {
	layout->m_参数槽 = nullptr;
	layout->m_参数类型 = nullptr;
	layout->m_绑定位置 = nullptr;
	layout->m_绑定数量 = nullptr;

	layout->m_绑定数量 = 0;
	layout->m_纹理槽 = nullptr;
}









Inline void f_alloc缓存槽(S_GPU参数布局* layout, uint16 num) {
	layout->m_绑定数量 = num;

	if (layout->m_参数槽) free(layout->m_参数槽);
	if (layout->m_绑定位置) free(layout->m_绑定位置);
	layout->m_参数槽 = (S_板载缓存**)calloc(layout->m_绑定数量, sizeof(S_板载缓存*));
	layout->m_绑定位置 = (uint8*)calloc(layout->m_绑定数量, sizeof(uint8));
	
	for (uint32 i = 0; i < layout->m_绑定数量; ++i) {
		layout->m_参数槽[i] = nullptr;
	}
	memset(layout->m_绑定位置, 0, layout->m_绑定数量 * sizeof(uint8));
}
Inline void f_alloc纹理槽(S_GPU参数布局* layout, uint16 num) {
	layout->m_纹理数量 = num;

	layout->m_纹理槽 = (S_纹理**)calloc(num, sizeof(S_纹理*));
	layout->m_纹理绑定位置 = (uint8*)calloc(layout->m_绑定数量, sizeof(uint8));
	
	for (uint32 i = 0; i < num; ++i) {
		layout->m_纹理槽[i] = nullptr;
		layout->m_纹理绑定位置[i] = DEF_BINDING_WIDGET_Texture;
	}
}


Inline void f_release缓存槽(S_GPU参数布局* layout) {
	free(layout->m_参数槽);
	free(layout->m_绑定位置);
	layout->m_绑定数量 = 0;
}
Inline void f_release纹理槽(S_GPU参数布局* layout) {
	free(layout->m_纹理槽);
	free(layout->m_纹理绑定位置);
	layout->m_纹理数量 = 0;
}
Inline void f_releaseGPU参数缓存槽(S_GPU参数槽* layout) {
	free(layout->m_参数槽);
	free(layout->m_绑定位置);
	layout->m_绑定数量 = 0;
}



uint32 f_getVk绘制方式(E_绘制方式 方式, E_绘图API apiName = E_绘图API::E_Vulkan);
uint32 f_getVk填充方式(E_填充模式 方式, E_绘图API apiName = E_绘图API::E_Vulkan);
uint32 f_getVk混合模式(E_混合模式 模式);
uint32 f_getVk混合因子(E_混合因子 因子);
uint32	f_get数据格式(E_数据格式 格式, E_绘图API apiName = E_绘图API::E_Vulkan);




struct S_光追后端 {
	S_设备环境*		m_Ctx;
	S_管线*			m_光追管线;
	S_结构指针		m_GPU参数设置;
	S_GPU参数槽		m_参数布局;
	

	static S_结构指针	g_加速结构创建命令缓存;
	static S_结构指针	g_渲染Fence;
	S_结构指针		m_渲染命令缓存;
	S_板载缓存*		m_顶层加速结构;
	S_GPU内存块		m_物体指针;
	S_GPU内存块		m_RtOb;
	
	S_纹理*			m_渲染纹理;

	S_板载缓存*		m_投影矩阵;
	

	S_纹理* m_渲染纹理_最终合成;
	S_纹理* m_渲染纹理_漫反射;
	S_纹理* m_渲染纹理_深度;
	S_纹理* m_渲染纹理_法线;
	S_纹理* m_渲染纹理_自发光;
	S_纹理* m_渲染纹理_光照;

	S_纹理采样器* m_渲染纹理采样器;


	//uint32	m_Frame;


	static S_板载缓存* m_帧渲染信息;
	

	static float32* m_f32_gpu_mapptr;
	static int32*   m_i32_gpu_mapptr;
	static vec2*    m_vec2_gpu_mapptr;
	static vec3*    m_vec3_gpu_mapptr;
	static GLSL_RenderFrame*	m_mapPtr_渲染帧数据;
	static uint8				g_光追列队;


	std::multimap<E_着色阶段, uint32> m_着色器组ID;


	
	bool           m_渲染;
	bool		   m_重新编译线管;
	S_着色器创建配置 m_线管创建配置信息;

	S_RayRenderAttr m_渲染器预览参数;
	S_RayRenderAttr m_渲染器渲染参数;
	S_Ray渲染配置	m_渲染配置;
	uvec2			m_瓦片大小;
	bool			m_分块渲染;

	bool			m_重新设置内部纹理传入参数;


	
	std::vector<S_纹理添加列队>      m_待加载纹理列队;
	static std::vector<S_MapPtrItem> G纹理;
	static std::vector<S_MapPtrItem> G字符纹理;
	static std::mutex                g_资源分配内存锁;

	static E_离线渲染状态 g_渲染状态;
	static uint32         g_物体全局显示模式;

	S_光追后端();
	virtual ~S_光追后端();

	virtual void f_重置() = 0;
	virtual void f_添加底层加速结构(S_Mesh* me, uint32 id, E_物体类型 ObType, uint32 实例材质位置) = 0;
	virtual void f_构建底层加速结构() = 0;
	virtual void f_清除几何加速结构() = 0;
	virtual void f_分配底层加速结构数量(uint32 num) = 0;
	virtual void f_构建顶层加速结构(uint32 num) = 0;
	//virtual void f_添加顶层加速结构(S_GPU内存块索引& TLAS, S_GPU内存块索引& 实例加速结构) = 0;
	virtual void f_清除顶层加速构建写入描述() = 0;
	//virtual void f_构建顶层加速结构() = 0;

	virtual void f_构建着色绑定列表() = 0;
	virtual void f_构建GPU参数布局(S_纹理& tex) = 0;

	virtual void f_构建BVH() = 0;
	virtual void f_Rander(GLSL_RenderFrame& 帧信息) = 0;
	virtual void f_Rander(GLSL_RenderFrame& 帧信息, uint32 采样次数) = 0;

	virtual bool f_更新实例变换(S_GPU内存块& BLAS, mat3X4 mat, uint32 id, uint32 ASID, uint8 实例材质ID, uint8 mask, uint32 预分配 = 0) = 0;
	//virtual bool f_更新实例变换(S_GPU内存块索引& BLAS, S_GPU内存块索引& 实例加速结构, Mat44f* mat, uint32 实例数量, uint32 底层ASID, uint8 实例材质ID, uint8 mask) = 0;
	virtual bool f_预分配实例变换(uint32 预分配){return true;};
	virtual void f_填充平行光参数(std::vector<S_LightParallel>& 平行光参数组) = 0;

	virtual void f_重构材质线管() = 0;
	virtual void f_重载() {};



	virtual void* f_get纹理(E_纹理分组类型 分组 = E_纹理分组类型::e_2D纹理) { return nullptr; }
	virtual void  f_add纹理(S_纹理* 纹理, uint32 loc, E_纹理分组类型 分组 = E_纹理分组类型::e_2D纹理) { }
	virtual void  f_set纹理(S_纹理* 纹理, E_纹理分组类型 分组 = E_纹理分组类型::e_2D纹理) {  }
	virtual void  f_rem纹理(uint32 loc, E_纹理分组类型 分组 = E_纹理分组类型::e_2D纹理) {  }
	virtual uint16 f_get纹理数量(E_纹理分组类型 分组 = E_纹理分组类型::e_2D纹理) { return 0; }

	int32 f_需要要加载纹理数();
	//void  f_添加纹理计数(int32 num);

	void	f_重置渲染帧记录();
	uint32	f_递增渲染帧记录();

	void f_mapGPU参数();
	void f_unmapGPU参数();
	void f_resizeGPU参数();



	virtual void f_刷新纹理GPU布局(){}


protected:
	int32 m_纹理绑定计数;
private:
	

};

